#include "p8x32a.h"
#include "p8x32acogpanel.h"
#include "p8x32adebugger.h"

#include "xpm_specs.h"

P8x32aDebugger::P8x32aDebugger() : lastCog(-1)
{
    QHBoxLayout *layout = new QHBoxLayout();

    coglist.append(&cog0);
    coglist.append(&cog1);
    coglist.append(&cog2);
    coglist.append(&cog3);
    coglist.append(&cog4);
    coglist.append(&cog5);
    coglist.append(&cog6);
    coglist.append(&cog7);

    for(int n = 0; n < P8x32a::COGCOUNT; n++) {
        tabs.addTab(coglist.at(n), tabText(n));
        coglist.at(n)->setCog(n);
    }

    hubram.setRowCount(P8x32a::RAMSIZE/HUBCOLS);
    hubram.setColumnCount(HUBCOLS);

    QStringList vlabels;
    for(int n = 0; n < P8x32a::RAMSIZE; n+= HUBCOLS)
        vlabels.append(QString("$%1").arg(n,4,16,QChar(QLatin1Char('0'))));
    hubram.setVerticalHeaderLabels(vlabels);

    QStringList hlabels;
    for(int n = 0; n < HUBCOLS; n++) {
        hlabels.append(QString("$%1").arg(n,2,16,QChar(QLatin1Char('0'))));
        hubram.setColumnWidth(n,QString("$00").length() *
            (hubram.fontMetrics().width(QChar(QLatin1Char('B')))+6));
    }
    hubram.setHorizontalHeaderLabels(hlabels);
    hubitem = new QList<QTableWidgetItem*>;
    tabs.addTab(&hubram, "HUB RAM");
    hubitem->setSharable(true);

    //hublayout->addWidget(&hubram, 6);
    //hublayout->addWidget(hubform, 1);
    //tabs.addTab(hublayout, "HUB");

    layout->addWidget(&tabs);
    setLayout(layout);

    tabs.setMovable(true);

    colorStackBase  = QColor(167,243,253);
    colorStackPtr   = QColor(Qt::cyan).darker(125);
    colorPubPtr     = QColor(167,210,253);
    colorVarStart   = QColor(255,223,191);
    colorObjStart   = QColor(255,191,191);
    colorClockMode  = QColor(253,243,168);
    colorClockFreq  = QColor(Qt::green).lighter();

    tabs.setCurrentIndex(0);
    setMinimumHeight(450);
}

P8x32aDebugger::~P8x32aDebugger()
{
    int count = hubitem->count();
    for(int n = 0; n < count; n++)
        delete hubitem->at(n);
    hubitem->clear();
#if 0
    QObjectList tabitems = tabs.children();
    for(int n = tabitems.count()-1; n > -1; n--) {
        delete tabitems.at(n);
    }
#endif
}

QString P8x32aDebugger::tabText(int n)
{
    return QString(" COG [%1]").arg(n);
}

QString P8x32aDebugger::tabTextActive(int n)
{
    return QString("*COG [%1]").arg(n);
}

void P8x32aDebugger::clearBreakpoints(int cog)
{
    coglist.at(cog)->clearBreakpoints();
}

void P8x32aDebugger::showBreakpoint(int cog, int line)
{
    tabs.setCurrentIndex(cog);
    coglist.at(cog)->showCogPC(line);
}

void P8x32aDebugger::clearCogMem(int cog)
{
    //tabs.setCurrentIndex(cog);
    coglist.at(cog)->clearCogMem();
    tabs.setTabText(cog,tabText(cog));
}

void P8x32aDebugger::addCogInstructions(int cog, QList<uint> code)
{
    //tabs.setCurrentIndex(cog);
    coglist.at(cog)->addCogInstructions(code);
}

void P8x32aDebugger::setCogPC(int cog, int pc)
{
    coglist.at(cog)->showCogPC(pc);
}

void P8x32aDebugger::showCogTab(int cog)
{
    tabs.setCurrentIndex(cog);
}

void P8x32aDebugger::showCog(int cog, CogInfo *info)
{
    // last tab is hubram ... don't change it.
    if(lastCog > -1)
        tabs.setTabText(lastCog, tabText(lastCog));
    tabs.setTabText(cog, tabTextActive(cog));
    coglist.at(cog)->showCog(info);
}

P8x32aCogPanel *P8x32aDebugger::cogPointer(int num)
{
    return coglist.at(num);
}

void P8x32aDebugger::clearHubMem()
{
    QTableWidgetItem *item;
    for(int n = 0; n < P8x32a::RAMSIZE; n++) {
        if((item = hubram.item(n/HUBCOLS,n%HUBCOLS)) != 0) {
            item->setText("");
            item->setBackgroundColor(Qt::white);
        }
    }
    hubitem->clear();
}

void P8x32aDebugger::showHubMem(uchar *memptr, int size)
{
    for(int n = 0; n < size; n++) {

        switch(n) {
            case 0x6:
                objBase = memptr[n];
                break;
            case 0x7:
                objBase |= memptr[n]<<8;
                break;
            case 0x8:
                varBase = memptr[n];
                break;
            case 0x9:
                varBase |= memptr[n]<<8;
                break;
            case 0xA:
                stackBase = memptr[n];
                break;
            case 0xB:
                stackBase |= memptr[n]<<8;
                stackMark = stackBase - 8;
                break;
            case 0xC:
                pubPtr = memptr[n];
                break;
            case 0xD:
                pubPtr |= memptr[n]<<8;
                break;
            case 0xE:
                stackPtr = memptr[n];
                break;
            case 0xF:
                stackPtr |= memptr[n]<<8;
                break;
        }

        QTableWidgetItem *item = new QTableWidgetItem(QString("$%1").arg(memptr[n],2,16,QChar(QLatin1Char('0'))));
        item->setFlags(Qt::ItemIsEnabled);
        item->setTextAlignment(Qt::AlignCenter);

        //qDebug() << "SP" << stackPtr << "SB" << stackBase << "VB" << varBase << "OB" << objBase << "PP" << pubPtr;


        if ((n & ~3) == 0) {
            item->setBackgroundColor(colorClockFreq);
        }
        else if((n & ~1) == 0x4) {
            item->setBackgroundColor(colorClockMode);
        }
        else if((n & ~1) == 0x6) {
            item->setBackgroundColor(colorObjStart);
        }
        else if((n & ~1) == 0x8) { // variable start
            item->setBackgroundColor(colorVarStart);
        }
        else if((n & ~1) == 0xA) { // stack start
            item->setBackgroundColor(colorStackBase);
        }
        else if((n & ~1) == 0xC) { // first pub address
            item->setBackgroundColor(colorPubPtr);
        }
        else if((n & ~1) == 0xE) { // initial stack pointer
            item->setBackgroundColor(colorStackPtr);
        }
        else if(n >= stackPtr)   { // stack pointer
            item->setBackgroundColor(colorStackPtr);
        }
        else if(n >= stackMark)   { // stack markers
            item->setBackgroundColor(colorStackBase);
        }
        else if(n >= varBase) { // variable start
            item->setBackgroundColor(colorVarStart);
        }
        else if(n >= pubPtr) { // first pub address
            item->setBackgroundColor(colorPubPtr);
        }
        else if(n >= objBase) { // objects+code
            item->setBackgroundColor(QColor(Qt::red).lighter());
        }

        hubram.setItem(n/HUBCOLS,n%HUBCOLS,item);
    }
}

void P8x32aDebugger::pokeHubMem(int addr, int value, int size)
{
    QTableWidgetItem *item;
    int count = hubitem->count();
    for(int n = 0; n < size; n++) {
        int address = addr+n;
        QColor color(Qt::white);

        if(address >= stackPtr)
            color = colorStackPtr;
        else if(address >= stackBase)
            color = colorStackBase;
        else if(address >= varBase)
            color = colorVarStart;
        else if((address & ~1) == objBase)
            color = colorObjStart;
        else if((address & ~1) == pubPtr)
            color = colorPubPtr;

        if(count < address) {
            item = new QTableWidgetItem(QString("$%1").arg(value&0xff,2,16,QChar(QLatin1Char('0'))));
            hubram.setItem(address/HUBCOLS,address%HUBCOLS,item);
            //item->setBackgroundColor(QColor(Qt::cyan).darker(125));
        } else {
            if((item = hubram.item(address/HUBCOLS,address%HUBCOLS)) != 0) {
                item->setText(QString("$%1").arg(value&0xff,2,16,QChar(QLatin1Char('0'))));
            }
        }
        item->setBackgroundColor(color);
        value >>= 8;
    }
}
